﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	CamlQueryBuilder.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;
using System.Collections.Generic;

namespace Smart.Common.Entities
{
	/// <summary>
	/// Query Builder
	/// </summary>
	public class CamlQueryBuilder<TExecutorType> : IQueryBuilder<TExecutorType>
		where TExecutorType : class
	{
		/// <summary>
		/// Fields Metadata
		/// </summary>
		public MetaFields Meta { get; set; }

		/// <summary>
		/// Where part of QueryBuilder query
		/// </summary>
		public IQueryBuilderWhere<TExecutorType> Where { get; protected set; }

		/// <summary>
		/// OrderBy part of QueryBuilder query
		/// </summary>
		public IQueryBuilderOrderBy<TExecutorType> OrderBy { get; protected set; }

		/// <summary>
		/// GroupBy part of QueryBuilder query
		/// </summary>
		public IQueryBuilderGroupBy<TExecutorType> GroupBy { get; protected set; }

		/// <summary>
		/// Query executor
		/// </summary>
		public TExecutorType Executor { get; protected set; }

		/// <summary>
		/// Query Builder
		/// </summary>
		/// <param name="meta">Fields metadata to query</param>
		/// <param name="executor">Query executor</param>
		public CamlQueryBuilder(MetaFields meta, TExecutorType executor)
		{
			Meta = meta;
			Executor = executor;

			Where = new CamlQueryBuilderWhere<TExecutorType> { Query = this };
			OrderBy = new CamlQueryBuilderOrderBy<TExecutorType> { Query = this };
			GroupBy = new CamlQueryBuilderGroupBy<TExecutorType> { Query = this };
		}

		/// <summary>
		/// Filter field using op
		/// </summary>
		public virtual IQueryBuilder<TExecutorType> Filter(string field, FilterCondition op)
		{
			Where.Filter(field, op);

			return this;
		}

		/// <summary>
		/// Filter field using op and value
		/// </summary>
		public virtual IQueryBuilder<TExecutorType> Filter(string field, FilterCondition op, object value)
		{
			Where.Filter(field, op, value);

			return this;
		}

		/// <summary>
		/// Sort by field
		/// </summary>
		public virtual IQueryBuilder<TExecutorType> Sort(string field, bool asc)
		{
			OrderBy.Sort(field, asc);

			return this;
		}

		/// <summary>
		/// Group by field
		/// </summary>
		public virtual IQueryBuilder<TExecutorType> Group(string field)
		{
			GroupBy.Field(field);

			return this;
		}

		/// <summary>
		/// Format QueryBuilder Query (Where, OrderBy, GroupBy)
		/// </summary>
		public virtual string FormatQuery()
		{
			return
				Where.FormatQuery() +
				OrderBy.FormatQuery() +
				GroupBy.FormatQuery();
		}

		/// <summary>
		/// Return Query properties
		/// </summary>
		public Dictionary<string, object> GetProperties()
		{
			var props = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

			if (Where.IsDateRangesOverlapUsed)
			{
				props["ExpandRecurrence"] = true;

				var filters = Where.FindRecursive("DateRangesOverlap");

				if (filters.Count > 1)
					throw new InvalidOperationException("Query should contain only one DateRangesOverlap filter!");

				var item = (CamlQueryBuilderDateRangesOverlapItem<TExecutorType>)filters[0];

				if (item.ValueS.IsNullOrEmpty())
				{
					props["CalendarDate"] = item.ValueDT;
				}
			}

			return props;
		}

		/// <summary>
		/// Return casted query executor
		/// </summary>
		public TMyExecutorType GetExecutor<TMyExecutorType>()
			where TMyExecutorType : TExecutorType
		{
			return (TMyExecutorType)Executor;
		}
	}
}